home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / tack / edit.c < prev    next >
C/C++ Source or Header  |  2002-10-24  |  21KB  |  978 lines

  1. /*
  2. ** Copyright (C) 1997 Free Software Foundation, Inc.
  3. ** 
  4. ** This file is part of TACK.
  5. ** 
  6. ** TACK is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2, or (at your option)
  9. ** any later version.
  10. ** 
  11. ** TACK is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** 
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with TACK; see the file COPYING.  If not, write to
  18. ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. ** Boston, MA 02111-1307, USA.
  20. */
  21.  
  22. #include <tack.h>
  23. #include <time.h>
  24. #include <tic.h>
  25.  
  26. MODULE_ID("$Id: edit.c,v 1.8 2001/06/18 18:44:32 tom Exp $")
  27.  
  28. /*
  29.  * Terminfo edit features
  30.  */
  31. static void show_info(struct test_list *, int *, int *);
  32. static void show_value(struct test_list *, int *, int *);
  33. static void show_untested(struct test_list *, int *, int *);
  34. static void show_changed(struct test_list *, int *, int *);
  35.  
  36. #define SHOW_VALUE    1
  37. #define SHOW_EDIT    2
  38. #define SHOW_DELETE    3
  39.  
  40. struct test_list edit_test_list[] = {
  41.     {MENU_CLEAR, 0, 0, 0, "i) display current terminfo", show_info, 0},
  42.     {0, 0, 0, 0, "w) write the current terminfo to a file", save_info, 0},
  43.     {SHOW_VALUE, 3, 0, 0, "v) show value of a selected cap", show_value, 0},
  44.     {SHOW_EDIT, 4, 0, 0, "e) edit value of a selected cap", show_value, 0},
  45.     {SHOW_DELETE, 3, 0, 0, "d) delete string", show_value, 0},
  46.     {0, 3, 0, 0, "m) show caps that have been modified", show_changed, 0},
  47.     {MENU_CLEAR + FLAG_CAN_TEST, 0, 0, 0, "c) show caps that can be tested", show_report, 0},
  48.     {MENU_CLEAR + FLAG_TESTED, 0, 0, 0, "t) show caps that have been tested", show_report, 0},
  49.     {MENU_CLEAR + FLAG_FUNCTION_KEY, 0, 0, 0, "f) show a list of function keys", show_report, 0},
  50.     {MENU_CLEAR, 0, 0, 0, "u) show caps defined that can not be tested", show_untested, 0},
  51.     {MENU_LAST, 0, 0, 0, 0, 0, 0}
  52. };
  53.  
  54. static char change_pad_text[MAX_CHANGES][80];
  55. struct test_list change_pad_list[MAX_CHANGES] = {
  56.     {MENU_LAST, 0, 0, 0, 0, 0, 0}
  57. };
  58.  
  59. static void build_change_menu(struct test_menu *);
  60. static void change_one_entry(struct test_list *, int *, int *);
  61.  
  62. struct test_menu change_pad_menu = {
  63.     0, 'q', 0,
  64.     "Select cap name", "change", 0,
  65.     build_change_menu, change_pad_list, 0, 0, 0
  66. };
  67.  
  68. extern struct test_results *pads[STRCOUNT];    /* save pad results here */
  69.  
  70. static TERMTYPE    original_term;        /* terminal type description */
  71.  
  72. static char flag_boolean[BOOLCOUNT];    /* flags for booleans */
  73. static char flag_numerics[NUMCOUNT];    /* flags for numerics */
  74. static char flag_strings[STRCOUNT];    /* flags for strings */
  75. static int xon_index;            /* Subscript for (xon) */
  76. int xon_shadow;
  77.  
  78. static int start_display;        /* the display has just started */
  79. static int display_lines;        /* number of lines displayed */
  80.  
  81. /*
  82. **    send_info_string(str)
  83. **
  84. **    Return the terminfo string prefixed by the correct separator
  85. */
  86. static void
  87. send_info_string(
  88.     const char *str,
  89.     int *ch)
  90. {
  91.     int len;
  92.  
  93.     if (display_lines == -1) {
  94.         return;
  95.     }
  96.     len = strlen(str);
  97.     if (len + char_count + 3 >= columns) {
  98.         if (start_display == 0) {
  99.             put_str(",");
  100.         }
  101.         put_crlf();
  102.         if (++display_lines > lines) {
  103.             ptext("-- more -- ");
  104.             *ch = wait_here();
  105.             if (*ch == 'q') {
  106.                 display_lines = -1;
  107.                 return;
  108.             }
  109.             display_lines = 0;
  110.         }
  111.         if (len >= columns) {
  112.             /* if the terminal does not (am) then this loses */
  113.             if (columns) {
  114.                 display_lines += ((strlen(str) + 3) / columns) + 1;
  115.             }
  116.             put_str("   ");
  117.             put_str(str);
  118.             start_display = 0;
  119.             return;
  120.         }
  121.         ptext("   ");
  122.     } else
  123.     if (start_display == 0) {
  124.         ptext(", ");
  125.     } else {
  126.         ptext("   ");
  127.     }
  128.     ptext(str);
  129.     start_display = 0;
  130. }
  131.  
  132. /*
  133. **    show_info(test_list, status, ch)
  134. **
  135. **    Display the current terminfo
  136. */
  137. static void
  138. show_info(
  139.     struct test_list *t GCC_UNUSED,
  140.     int *state GCC_UNUSED,
  141.     int *ch)
  142. {
  143.     int i;
  144.     char buf[1024];
  145.  
  146.     display_lines = 1;
  147.     start_display = 1;
  148.     for (i = 0; i < BOOLCOUNT; i++) {
  149.         if ((i == xon_index) ? xon_shadow : CUR Booleans[i]) {
  150.             send_info_string(boolnames[i], ch);
  151.         }
  152.     }
  153.     for (i = 0; i < NUMCOUNT; i++) {
  154.         if (CUR Numbers[i] >= 0) {
  155.             sprintf(buf, "%s#%d", numnames[i], CUR Numbers[i]);
  156.             send_info_string(buf, ch);
  157.         }
  158.     }
  159.     for (i = 0; i < STRCOUNT; i++) {
  160.         if (CUR Strings[i]) {
  161.             sprintf(buf, "%s=%s", strnames[i],
  162.                 print_expand(CUR Strings[i]));
  163.             send_info_string(buf, ch);
  164.         }
  165.     }
  166.     put_newlines(2);
  167.     *ch = REQUEST_PROMPT;
  168. }
  169.  
  170. /*
  171. **    save_info_string(str, fp)
  172. **
  173. **    Write the terminfo string prefixed by the correct separator
  174. */
  175. static void
  176. save_info_string(
  177.     const char *str,
  178.     FILE *fp)
  179. {
  180.     int len;
  181.  
  182.     len = strlen(str);
  183.     if (len + display_lines >= 77) {
  184.         if (display_lines > 0) {
  185.             (void) fprintf(fp, "\n\t");
  186.         }
  187.         display_lines = 8;
  188.     } else
  189.     if (display_lines > 0) {
  190.         (void) fprintf(fp, " ");
  191.         display_lines++;
  192.     } else {
  193.         (void) fprintf(fp, "\t");
  194.         display_lines = 8;
  195.     }
  196.     (void) fprintf(fp, "%s,", str);
  197.     display_lines += len + 1;
  198. }
  199.  
  200. /*
  201. **    save_info(test_list, status, ch)
  202. **
  203. **    Write the current terminfo to a file
  204. */
  205. void
  206. save_info(
  207.     struct test_list *t,
  208.     int *state,
  209.     int *ch)
  210. {
  211.     int i;
  212.     FILE *fp;
  213.     time_t now;
  214.     char buf[1024];
  215.  
  216.     if ((fp = fopen(tty_basename, "w")) == (FILE *) NULL) {
  217.         (void) sprintf(temp, "can't open: %s", tty_basename);
  218.         ptextln(temp);
  219.         generic_done_message(t, state, ch);
  220.         return;
  221.     }
  222.     time(&now);
  223.     /* Note: ctime() returns a newline at the end of the string */
  224.     (void) fprintf(fp, "# Terminfo created by TACK for TERM=%s on %s",
  225.         tty_basename, ctime(&now));
  226.     (void) fprintf(fp, "%s|%s,\n", tty_basename, longname());
  227.  
  228.     display_lines = 0;
  229.     for (i = 0; i < BOOLCOUNT; i++) {
  230.         if (i == xon_index ? xon_shadow : CUR Booleans[i]) {
  231.             save_info_string(boolnames[i], fp);
  232.         }
  233.     }
  234.     for (i = 0; i < NUMCOUNT; i++) {
  235.         if (CUR Numbers[i] >= 0) {
  236.             sprintf(buf, "%s#%d", numnames[i], CUR Numbers[i]);
  237.             save_info_string(buf, fp);
  238.         }
  239.     }
  240.     for (i = 0; i < STRCOUNT; i++) {
  241.         if (CUR Strings[i]) {
  242.             sprintf(buf, "%s=%s", strnames[i],
  243.                 _nc_tic_expand(CUR Strings[i], TRUE, TRUE));
  244.             save_info_string(buf, fp);
  245.         }
  246.     }
  247.     (void) fprintf(fp, "\n");
  248.     (void) fclose(fp);
  249.     sprintf(temp, "Terminfo saved as file: %s", tty_basename);
  250.     ptextln(temp);
  251. }
  252.  
  253. /*
  254. **    show_value(test_list, status, ch)
  255. **
  256. **    Display the value of a selected cap
  257. */
  258. static void
  259. show_value(
  260.     struct test_list *t,
  261.     int *state GCC_UNUSED,
  262.     int *ch)
  263. {
  264.     struct name_table_entry const *nt;
  265.     char *s;
  266.     int n, op, b;
  267.     char buf[1024];
  268.     char tmp[1024];
  269.  
  270.     ptext("enter name: ");
  271.     read_string(buf, 80);
  272.     if (buf[0] == '\0' || buf[1] == '\0') {
  273.         *ch = buf[0];
  274.         return;
  275.     }
  276.     if (line_count + 2 >= lines) {
  277.         put_clear();
  278.     }
  279.     op = t->flags & 255;
  280.     if ((nt = _nc_find_entry(buf, _nc_info_hash_table))) {
  281.         switch (nt->nte_type) {
  282.         case BOOLEAN:
  283.             if (op == SHOW_DELETE) {
  284.                 if (nt->nte_index == xon_index) {
  285.                     xon_shadow = 0;
  286.                 } else {
  287.                     CUR Booleans[nt->nte_index] = 0;
  288.                 }
  289.                 return;
  290.             }
  291.             b = nt->nte_index == xon_index ? xon_shadow :
  292.                 CUR Booleans[nt->nte_index];
  293.             sprintf(temp, "boolean  %s %s", buf,
  294.                 b ? "True" : "False");
  295.             break;
  296.         case STRING:
  297.             if (op == SHOW_DELETE) {
  298.                 CUR Strings[nt->nte_index] = (char *) 0;
  299.                 return;
  300.             }
  301.             if (CUR Strings[nt->nte_index]) {
  302.                 sprintf(temp, "string  %s %s", buf,
  303.                     expand(CUR Strings[nt->nte_index]));
  304.             } else {
  305.                 sprintf(temp, "undefined string %s", buf);
  306.             }
  307.             break;
  308.         case NUMBER:
  309.             if (op == SHOW_DELETE) {
  310.                 CUR Numbers[nt->nte_index] = -1;
  311.                 return;
  312.             }
  313.             sprintf(temp, "numeric  %s %d", buf,
  314.                 CUR Numbers[nt->nte_index]);
  315.             break;
  316.         default:
  317.             sprintf(temp, "unknown");
  318.             break;
  319.         }
  320.         ptextln(temp);
  321.     } else {
  322.         sprintf(temp, "Cap not found: %s", buf);
  323.         ptextln(temp);
  324.         return;
  325.     }
  326.     if (op != SHOW_EDIT) {
  327.         return;
  328.     }
  329.     if (nt->nte_type == BOOLEAN) {
  330.         ptextln("Value flipped");
  331.         if (nt->nte_index == xon_index) {
  332.             xon_shadow = !xon_shadow;
  333.         } else {
  334.             CUR Booleans[nt->nte_index] = !CUR Booleans[nt->nte_index];
  335.         }
  336.         return;
  337.     }
  338.     ptextln("Enter new value");
  339.     read_string(buf, sizeof(buf));
  340.  
  341.     switch (nt->nte_type) {
  342.     case STRING:
  343.         _nc_reset_input((FILE *) 0, buf);
  344.         _nc_trans_string(tmp, tmp + sizeof(tmp));
  345.         s = (char *)malloc(strlen(tmp) + 1);
  346.         strcpy(s, tmp);
  347.         CUR Strings[nt->nte_index] = s;
  348.         sprintf(temp, "new string value  %s", nt->nte_name);
  349.         ptextln(temp);
  350.         ptextln(expand(CUR Strings[nt->nte_index]));
  351.         break;
  352.     case NUMBER:
  353.         if (sscanf(buf, "%d", &n) == 1) {
  354.             CUR Numbers[nt->nte_index] = n;
  355.             sprintf(temp, "new numeric value  %s %d",
  356.                 nt->nte_name, n);
  357.             ptextln(temp);
  358.         } else {
  359.             sprintf(temp, "Illegal number: %s", buf);
  360.             ptextln(temp);
  361.         }
  362.         break;
  363.     default:
  364.         break;
  365.     }
  366. }
  367.  
  368. /*
  369. **    get_string_cap_byname(name, long_name)
  370. **
  371. **    Given a cap name, find the value
  372. **    Errors are quietly ignored.
  373. */
  374. char *
  375. get_string_cap_byname(
  376.     const char *name,
  377.     const char **long_name)
  378. {
  379.     struct name_table_entry const *nt;
  380.  
  381.     if ((nt = _nc_find_entry(name, _nc_info_hash_table))) {
  382.         if (nt->nte_type == STRING) {
  383.             *long_name = strfnames[nt->nte_index];
  384.             return (CUR Strings[nt->nte_index]);
  385.         }
  386.     }
  387.     *long_name = "??";
  388.     return (char *) 0;
  389. }
  390.  
  391. /*
  392. **    get_string_cap_byvalue(value)
  393. **
  394. **    Given a capability string, find its position in the data base.
  395. **    Return the index or -1 if not found.
  396. */
  397. int
  398. get_string_cap_byvalue(
  399.     const char *value)
  400. {
  401.     int i;
  402.  
  403.     if (value) {
  404.         for (i = 0; i < STRCOUNT; i++) {
  405.             if (CUR Strings[i] == value) {
  406.                 return i;
  407.             }
  408.         }
  409.         /* search for translated strings */
  410.         for (i = 0; i < TM_last; i++) {
  411.             if (TM_string[i].value == value) {
  412.                 return TM_string[i].index;
  413.             }
  414.         }
  415.     }
  416.     return -1;
  417. }
  418.  
  419. /*
  420. **    show_changed(test_list, status, ch)
  421. **
  422. **    Display a list of caps that have been changed.
  423. */
  424. static void
  425. show_changed(
  426.     struct test_list *t GCC_UNUSED,
  427.     int *state GCC_UNUSED,
  428.     int *ch)
  429. {
  430.     int i, header = 1, v;
  431.     const char *a;
  432.     const char *b;
  433.     static char title[] = "                     old value   cap  new value";
  434.     char abuf[1024];
  435.  
  436.     for (i = 0; i < BOOLCOUNT; i++) {
  437.         v = (i == xon_index) ? xon_shadow : CUR Booleans[i];
  438.         if (original_term.Booleans[i] != v) {
  439.             if (header) {
  440.                 ptextln(title);
  441.                 header = 0;
  442.             }
  443.             sprintf(temp, "%30d %6s %d",
  444.                 original_term.Booleans[i], boolnames[i], v);
  445.             ptextln(temp);
  446.         }
  447.     }
  448.     for (i = 0; i < NUMCOUNT; i++) {
  449.         if (original_term.Numbers[i] != CUR Numbers[i]) {
  450.             if (header) {
  451.                 ptextln(title);
  452.                 header = 0;
  453.             }
  454.             sprintf(temp, "%30d %6s %d",
  455.                 original_term.Numbers[i], numnames[i],
  456.                 CUR Numbers[i]);
  457.             ptextln(temp);
  458.         }
  459.     }
  460.     for (i = 0; i < STRCOUNT; i++) {
  461.         a = original_term.Strings[i] ? original_term.Strings[i] : "";
  462.         b = CUR Strings[i] ?  CUR Strings[i] : "";
  463.         if (strcmp(a, b)) {
  464.             if (header) {
  465.                 ptextln(title);
  466.                 header = 0;
  467.             }
  468.             strcpy(abuf, _nc_tic_expand(a, TRUE, TRUE));
  469.             sprintf(temp, "%30s %6s %s", abuf, strnames[i],
  470.                 _nc_tic_expand(b, TRUE, TRUE));
  471.             putln(temp);
  472.         }
  473.     }
  474.     if (header) {
  475.         ptextln("No changes");
  476.     }
  477.     put_crlf();
  478.     *ch = REQUEST_PROMPT;
  479. }
  480.  
  481. /*
  482. **    user_modified()
  483. **
  484. **    Return TRUE if the user has modified the terminfo
  485. */
  486. int
  487. user_modified(void)
  488. {
  489.     const char *a, *b;
  490.     int i, v;
  491.  
  492.     for (i = 0; i < BOOLCOUNT; i++) {
  493.         v = (i == xon_index) ? xon_shadow : CUR Booleans[i];
  494.         if (original_term.Booleans[i] != v) {
  495.             return TRUE;
  496.         }
  497.     }
  498.     for (i = 0; i < NUMCOUNT; i++) {
  499.         if (original_term.Numbers[i] != CUR Numbers[i]) {
  500.             return TRUE;
  501.         }
  502.     }
  503.     for (i = 0; i < STRCOUNT; i++) {
  504.         a = original_term.Strings[i] ? original_term.Strings[i] : "";
  505.         b = CUR Strings[i] ?  CUR Strings[i] : "";
  506.         if (strcmp(a, b)) {
  507.             return TRUE;
  508.         }
  509.     }
  510.     return FALSE;
  511. }
  512.  
  513. /*****************************************************************************
  514.  *
  515.  * Maintain the list of capabilities that can be tested
  516.  *
  517.  *****************************************************************************/
  518.  
  519. /*
  520. **    mark_cap(name, flag)
  521. **
  522. **    Mark the cap data base with the flag provided.
  523. */
  524. static void
  525. mark_cap(
  526.     char *name,
  527.     int flag)
  528. {
  529.     struct name_table_entry const *nt;
  530.  
  531.     if ((nt = _nc_find_entry(name, _nc_info_hash_table))) {
  532.         switch (nt->nte_type) {
  533.         case BOOLEAN:
  534.             flag_boolean[nt->nte_index] |= flag;
  535.             break;
  536.         case STRING:
  537.             flag_strings[nt->nte_index] |= flag;
  538.             break;
  539.         case NUMBER:
  540.             flag_numerics[nt->nte_index] |= flag;
  541.             break;
  542.         default:
  543.             sprintf(temp, "unknown cap type (%s)", name);
  544.             ptextln(temp);
  545.             break;
  546.         }
  547.     } else {
  548.         sprintf(temp, "Cap not found: %s", name);
  549.         ptextln(temp);
  550.         (void) wait_here();
  551.     }
  552. }
  553.  
  554. /*
  555. **    can_test(name-list, flags)
  556. **
  557. **    Scan the name list and get the names.
  558. **    Enter each name into the can-test data base.
  559. **    <space> ( and ) may be used as separators.
  560. */
  561. void
  562. can_test(
  563.     const char *s,
  564.     int flags)
  565. {
  566.     int ch, j;
  567.     char name[32];
  568.  
  569.     if (s) {
  570.         for (j = 0; (name[j] = ch = *s); s++) {
  571.             if (ch == ' ' || ch == ')' || ch == '(') {
  572.                 if (j) {
  573.                     name[j] = '\0';
  574.                     mark_cap(name, flags);
  575.                 }
  576.                 j = 0;
  577.             } else {
  578.                 j++;
  579.             }
  580.         }
  581.         if (j) {
  582.             mark_cap(name, flags);
  583.         }
  584.     }
  585. }
  586.  
  587. /*
  588. **    cap_index(name-list, index-list)
  589. **
  590. **    Scan the name list and return a list of indexes.
  591. **    <space> ( and ) may be used as separators.
  592. **    This list is terminated with -1.
  593. */
  594. void
  595. cap_index(
  596.     const char *s,
  597.     int *inx)
  598. {
  599.     struct name_table_entry const *nt;
  600.     int ch, j;
  601.     char name[32];
  602.  
  603.     if (s) {
  604.         for (j = 0; ; s++) {
  605.             name[j] = ch = *s;
  606.             if (ch == ' ' || ch == ')' || ch == '(' || ch == 0) {
  607.                 if (j) {
  608.                     name[j] = '\0';
  609.                     if ((nt = _nc_find_entry(name,
  610.                         _nc_info_hash_table)) &&
  611.                         (nt->nte_type == STRING)) {
  612.                         *inx++ = nt->nte_index;
  613.                     }
  614.                 }
  615.                 if (ch == 0) {
  616.                     break;
  617.                 }
  618.                 j = 0;
  619.             } else {
  620.                 j++;
  621.             }
  622.         }
  623.     }
  624.     *inx = -1;
  625. }
  626.  
  627. /*
  628. **    cap_match(name-list, cap)
  629. **
  630. **    Scan the name list and see if the cap is in the list.
  631. **    Return TRUE if we find an exact match.
  632. **    <space> ( and ) may be used as separators.
  633. */
  634. int
  635. cap_match(
  636.     const char *names,
  637.     const char *cap)
  638. {
  639.     char *s;
  640.     int c, l, t;
  641.  
  642.     if (names) {
  643.         l = strlen(cap);
  644.         while ((s = strstr(names, cap))) {
  645.             c = (names == s) ? 0 : *(s - 1);
  646.             t = s[l];
  647.             if ((c == 0 || c == ' ' || c == '(') &&
  648.                 (t == 0 || t == ' ' || t == ')')) {
  649.                 return TRUE;
  650.             }
  651.             if (t == 0) {
  652.                 break;
  653.             }
  654.             names = s + l;
  655.         }
  656.     }
  657.     return FALSE;
  658. }
  659.  
  660. /*
  661. **    show_report(test_list, status, ch)
  662. **
  663. **    Display a list of caps that can be tested
  664. */
  665. void
  666. show_report(
  667.     struct test_list *t,
  668.     int *state GCC_UNUSED,
  669.     int *ch)
  670. {
  671.     int i, j, nc, flag;
  672.     const char *s;
  673.     const char *nx[BOOLCOUNT + NUMCOUNT + STRCOUNT];
  674.  
  675.     flag = t->flags & 255;
  676.     nc = 0;
  677.     for (i = 0; i < BOOLCOUNT; i++) {
  678.         if (flag_boolean[i] & flag) {
  679.             nx[nc++] = boolnames[i];
  680.         }
  681.     }
  682.     for (i = 0; i < NUMCOUNT; i++) {
  683.         if (flag_numerics[i] & flag) {
  684.             nx[nc++] = numnames[i];
  685.         }
  686.     }
  687.     for (i = 0; i < STRCOUNT; i++) {
  688.         if (flag_strings[i] & flag) {
  689.             nx[nc++] = strnames[i];
  690.         }
  691.     }
  692.     /* sort */
  693.     for (i = 0; i < nc - 1; i++) {
  694.         for (j = i + 1; j < nc; j++) {
  695.             if (strcmp(nx[i], nx[j]) > 0) {
  696.                 s = nx[i];
  697.                 nx[i] = nx[j];
  698.                 nx[j] = s;
  699.             }
  700.         }
  701.     }
  702.     if (flag & FLAG_FUNCTION_KEY) {
  703.         ptextln("The following function keys can be tested:");
  704.     } else
  705.     if (flag & FLAG_CAN_TEST) {
  706.         ptextln("The following capabilities can be tested:");
  707.     } else
  708.     if (flag & FLAG_TESTED) {
  709.         ptextln("The following capabilities have been tested:");
  710.     }
  711.     put_crlf();
  712.     for (i = 0; i < nc; i++) {
  713.         sprintf(temp, "%s ", nx[i]);
  714.         ptext(temp);
  715.     }
  716.     put_newlines(1);
  717.     *ch = REQUEST_PROMPT;
  718. }
  719.  
  720. /*
  721. **    show_untested(test_list, status, ch)
  722. **
  723. **    Display a list of caps that are defined but cannot be tested.
  724. **    Don't bother to sort this list.
  725. */
  726. static void
  727. show_untested(
  728.     struct test_list *t GCC_UNUSED,
  729.     int *state GCC_UNUSED,
  730.     int *ch)
  731. {
  732.     int i;
  733.  
  734.     ptextln("Caps that are defined but cannot be tested:");
  735.     for (i = 0; i < BOOLCOUNT; i++) {
  736.         if (flag_boolean[i] == 0 && CUR Booleans[i]) {
  737.             sprintf(temp, "%s ", boolnames[i]);
  738.             ptext(temp);
  739.         }
  740.     }
  741.     for (i = 0; i < NUMCOUNT; i++) {
  742.         if (flag_numerics[i] == 0 && CUR Numbers[i] >= 0) {
  743.             sprintf(temp, "%s ", numnames[i]);
  744.             ptext(temp);
  745.         }
  746.     }
  747.     for (i = 0; i < STRCOUNT; i++) {
  748.         if (flag_strings[i] == 0 && CUR Strings[i]) {
  749.             sprintf(temp, "%s ", strnames[i]);
  750.             ptext(temp);
  751.         }
  752.     }
  753.     put_newlines(1);
  754.     *ch = REQUEST_PROMPT;
  755. }
  756.  
  757. /*
  758. **    edit_init()
  759. **
  760. **    Initialize the function key data base
  761. */
  762. void
  763. edit_init(void)
  764. {
  765.     int i, j, lc;
  766.     char *lab;
  767.     struct name_table_entry const *nt;
  768.     int label_strings[STRCOUNT];
  769.  
  770.     _nc_copy_termtype(&original_term, &cur_term->type);
  771.     for (i = 0; i < BOOLCOUNT; i++) {
  772.         original_term.Booleans[i] = CUR Booleans[i];
  773.     }
  774.     for (i = 0; i < NUMCOUNT; i++) {
  775.         original_term.Numbers[i] = CUR Numbers[i];
  776.     }
  777.     /* scan for labels */
  778.     for (i = lc = 0; i < STRCOUNT; i++) {
  779.         original_term.Strings[i] = CUR Strings[i];
  780.         if (strncmp(strnames[i], "lf", 2) == 0) {
  781.             flag_strings[i] |= FLAG_LABEL;
  782.             if (CUR Strings[i]) {
  783.                 label_strings[lc++] = i;
  784.             }
  785.         }
  786.     }
  787.     /* scan for function keys */
  788.     for (i = 0; i < STRCOUNT; i++) {
  789.         if ((strnames[i][0] == 'k') && strcmp(strnames[i], "kmous")) {
  790.             flag_strings[i] |= FLAG_FUNCTION_KEY;
  791.             lab = (char *) 0;
  792.             for (j = 0; j < lc; j++) {
  793.                 if (!strcmp(&strnames[i][1],
  794.                     &strnames[label_strings[j]][1])) {
  795.                     lab = CUR Strings[label_strings[j]];
  796.                     break;
  797.                 }
  798.             }
  799.             enter_key(strnames[i], CUR Strings[i], lab);
  800.         }
  801.     }
  802.     /* Lookup the translated strings */
  803.     for (i = 0; i < TM_last; i++) {
  804.         if ((nt = _nc_find_entry(TM_string[i].name,
  805.             _nc_info_hash_table)) && (nt->nte_type == STRING)) {
  806.             TM_string[i].index = nt->nte_index;
  807.         } else {
  808.             sprintf(temp, "TM_string lookup failed for: %s",
  809.                 TM_string[i].name);
  810.             ptextln(temp);
  811.         }
  812.     }
  813.     if ((nt = _nc_find_entry("xon", _nc_info_hash_table)) != 0) {
  814.         xon_index = nt->nte_index;
  815.     }
  816.     xon_shadow = xon_xoff;
  817. }
  818.  
  819. /*
  820. **    change_one_entry(test_list, status, ch)
  821. **
  822. **    Change the padding on the selected cap
  823. */
  824. static void
  825. change_one_entry(
  826.     struct test_list *test,
  827.     int *state,
  828.     int *chp)
  829. {
  830.     struct name_table_entry const *nt;
  831.     int i, j, x, star, slash,  v, dot, ch;
  832.     const char *s;
  833.     char *t, *p;
  834.     const char *current_string;
  835.     char buf[1024];
  836.     char pad[1024];
  837.  
  838.     i = test->flags & 255;
  839.     if (i == 255) {
  840.         /* read the cap name from the user */
  841.         ptext("enter name: ");
  842.         read_string(pad, 32);
  843.         if (pad[0] == '\0' || pad[1] == '\0') {
  844.             *chp = pad[0];
  845.             return;
  846.         }
  847.         if ((nt = _nc_find_entry(pad, _nc_info_hash_table)) &&
  848.             (nt->nte_type == STRING)) {
  849.             x = nt->nte_index;
  850.             current_string = CUR Strings[x];
  851.         } else {
  852.             sprintf(temp, "%s is not a string capability", pad);
  853.             ptext(temp);
  854.             generic_done_message(test, state, chp);
  855.             return;
  856.         }
  857.     } else {
  858.         x = tx_index[i];
  859.         current_string = tx_cap[i];
  860.         strcpy(pad, strnames[x]);
  861.     }
  862.     if (!current_string) {
  863.         ptextln("That string is not currently defined.  Please enter a new value, including the padding delay:");
  864.         read_string(buf, sizeof(buf));
  865.         _nc_reset_input((FILE *) 0, buf);
  866.         _nc_trans_string(pad, pad + sizeof(pad));
  867.         t = (char *)malloc(strlen(pad) + 1);
  868.         strcpy(t, pad);
  869.         CUR Strings[x] = t;
  870.         sprintf(temp, "new string value  %s", strnames[x]);
  871.         ptextln(temp);
  872.         ptextln(expand(t));
  873.         return;
  874.     }
  875.     sprintf(buf, "Current value: (%s) %s", pad, _nc_tic_expand(current_string, TRUE, TRUE));
  876.     putln(buf);
  877.     ptextln("Enter new pad.  0 for no pad.  CR for no change.");
  878.     read_string(buf, 32);
  879.     if (buf[0] == '\0' || (buf[1] == '\0' && isalpha(UChar(buf[0])))) {
  880.         *chp = buf[0];
  881.         return;
  882.     }
  883.     star = slash = FALSE;
  884.     for (j = v = dot = 0; (ch = buf[j]); j++) {
  885.         if (ch >= '0' && ch <= '9') {
  886.             v = ch - '0' + v * 10;
  887.             if (dot) {
  888.                 dot++;
  889.             }
  890.         } else if (ch == '*') {
  891.             star = TRUE;
  892.         } else if (ch == '/') {
  893.             slash = TRUE;
  894.         } else if (ch == '.') {
  895.             dot = 1;
  896.         } else {
  897.             sprintf(temp, "Illegal character: %c", ch);
  898.             ptextln(temp);
  899.             ptext("General format:  99.9*/  ");
  900.             generic_done_message(test, state, chp);
  901.             return;
  902.         }
  903.     }
  904.     while (dot > 2) {
  905.         v /= 10;
  906.         dot--;
  907.     }
  908.     if (dot == 2) {
  909.         sprintf(pad, "%d.%d%s%s", v / 10, v % 10,
  910.                 star ? "*" : "", slash ? "/" : "");
  911.     } else {
  912.         sprintf(pad, "%d%s%s",
  913.             v, star ? "*" : "", slash ? "/" : "");
  914.     }
  915.     s = current_string;
  916.     t = buf;
  917.     for (v = 0; (ch = *t = *s++); t++) {
  918.         if (v == '$' && ch == '<') {
  919.             while ((ch = *s++) && (ch != '>'));
  920.             for (p = pad; (*++t = *p++); );
  921.             *t++ = '>';
  922.             while ((*t++ = *s++));
  923.             pad[0] = '\0';
  924.             break;
  925.         }
  926.         v = ch;
  927.     }
  928.     if (pad[0]) {
  929.         sprintf(t, "$<%s>", pad);
  930.     }
  931.     if ((t = (char *)malloc(strlen(buf) + 1))) {
  932.         strcpy(t, buf);
  933.         CUR Strings[x] = t;
  934.         if (i != 255) {
  935.             tx_cap[i] = t;
  936.         }
  937.     }
  938.     generic_done_message(test, state, chp);
  939. }
  940.  
  941. /*
  942. **    build_change_menu(menu_list)
  943. **
  944. **    Build the change pad menu list
  945. */
  946. static void
  947. build_change_menu(
  948.     struct test_menu *m)
  949. {
  950.     int i, j, k;
  951.     char *s;
  952.  
  953.     for (i = j = 0; i < txp; i++) {
  954.         if ((k = tx_index[i]) >= 0) {
  955.             s = _nc_tic_expand(tx_cap[i], TRUE, TRUE);
  956.             s[40] = '\0';
  957.             sprintf(change_pad_text[j], "%c) (%s) %s",
  958.                 'a' + j, strnames[k], s);
  959.             change_pad_list[j].flags = i;
  960.             change_pad_list[j].lines_needed = 4;
  961.             change_pad_list[j].menu_entry = change_pad_text[j];
  962.             change_pad_list[j].test_procedure = change_one_entry;
  963.             j++;
  964.         }
  965.     }
  966.     strcpy(change_pad_text[j], "z) enter name");
  967.     change_pad_list[j].flags = 255;
  968.     change_pad_list[j].lines_needed = 4;
  969.     change_pad_list[j].menu_entry = change_pad_text[j];
  970.     change_pad_list[j].test_procedure = change_one_entry;
  971.     j++;
  972.     change_pad_list[j].flags = MENU_LAST;
  973.     if (m->menu_title) {
  974.         put_crlf();
  975.         ptextln(m->menu_title);
  976.     }
  977. }
  978.